package other;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLOutput;
import java.util.*;
import java.util.stream.Stream;


public class apk {
    static int a = 0;
    static int b = 0;

    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();

//        String path = "C:\\Users\\chenyb\\Desktop\\apk_recompile";
        String path = "C:\\Users\\chenyb\\Desktop\\aa";
//        String saveApiPath = "C:\\Users\\chenyb\\Desktop\\apiTimes2.txt";
        Map<String, Map<String, Integer>> apkMap = new HashMap<>();

        // 1. 提取api特征
        File file = new File(path);
        if (file.exists()) {
            File[] apks = file.listFiles();
            for (File apk : apks) {
                System.out.println("-》 正在遍历apk: " + apk.getName());
                apkMap.put(apk.getName(), new HashMap<>());
                folderMethod(apk.getAbsolutePath(), apk.getName(), apkMap);
                System.out.println("《- 遍历结束，该apk调用api数为：" + apkMap.get(apk.getName()).size());
            }
        }
            // 2. 将api特征 存入txt
            for (Map.Entry entry : apkMap.entrySet()) {
                String apkName = (String) entry.getKey();
                Map<String, Integer> apiTimeMap = apkMap.get(apkName);
                System.out.println("other.apk " + apkName + " 调用次数前十的api：");
                sortAndSaveByValue(apiTimeMap, apkName);
            }

    }

    public static void folderMethod(String path, String apkName, Map<String, Map<String, Integer>> apkMap) {
        File file = new File(path);
        if (file.exists()) {
            File[] files = file.listFiles();
            if (null != files) {
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        folderMethod(file2.getAbsolutePath(), apkName, apkMap);
                    } else {
                        getApiBySmali(file2.getAbsolutePath(), apkName, apkMap);
                    }
                }
            }
        } else {
            System.out.println("文件不存在!");
        }
    }

    public static void getApiBySmali(String fileName, String apkName, Map<String, Map<String, Integer>> apkMap) {
        Map<String, Integer> apiTimeMap = apkMap.get(apkName);

        try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
            stream.forEach((String line) -> {
                String result = getApiByLine(line);
                if (result != "-1" && result.startsWith("android")) {
                    // 遍历每行 提取调用的 api
                    Integer apiTimes = apiTimeMap.get(result);
                    if (apiTimes == null) {
                        apiTimeMap.put(result, 1);
                    } else {
                        apiTimeMap.put(result, apiTimes + 1);
                    }
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据smali语法规则提取包名+函数名
     * 方法调用的表示格式: Lpackage/name/ObjectName;->MethodName(III)Z
     * 字段调用的表示格式: Lpackage/name/ObjectName;->FieldName:Ljava/lang/String;
     * <p>
     * 此方法代码参考自论文   =>   [1]陈红闵,胡江村.安卓恶意软件的静态检测方法[J].计算机系统应用,2018,27(07):26-33.
     */
    public static String getApiByLine(String str) {
        String result = "-1";

        if (str.lastIndexOf(";->") != -1) {
            String tempStr = str.substring(0, str.lastIndexOf(";->"));
            str = str.substring(str.lastIndexOf(";->") + 3);

            if (str.contains(":")) {
                //如果截取的字符串中包含冒号则代表这个是变量 否则为方法
            } else {
                String packegeName = tempStr.substring(tempStr.lastIndexOf(", ") + 1).trim();
                packegeName = packegeName.replaceAll("/", ".").substring(1);
                String methodName = str.substring(0, str.indexOf("("));
                result = packegeName + "." + methodName;
            }
        }
        return result;
    }


    public static String sortAndSaveByValue2(Map map, String apkName) {

        StringBuffer sb = new StringBuffer();
        List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
        Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
            //降序排序
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        for (Map.Entry<String, Integer> e : list) {
            sb.append(e.getKey() + " ");
        }
        return sb.toString();
    }

    public static void sortAndSaveByValue(Map map, String apkName) {

        try (FileWriter fw = new FileWriter("C:\\Users\\chenyb\\Desktop\\api2\\" + apkName + "-" + map.size() + ".txt")) {
            StringBuffer sb = new StringBuffer();
            List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
            Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
                //降序排序
                public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                    return o2.getValue().compareTo(o1.getValue());
                }
            });
            for (Map.Entry<String, Integer> e : list) {
                sb.append(e.getKey() + " ");
            }

            fw.write(sb.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
